package com.fast.fast.common.redis.config;

import com.fast.fast.common.base.constant.CacheConstants;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

/**
 * Redis配置类
 *
 * @author lyf
 * @date 2022/01/01 00:00 周六
 **/
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
@AutoConfiguration
public class RedisConfig {

    /**
     * 使用StringRedisSerializer来序列化对象在redis中的key值
     */
    private static final RedisSerializer<String> KEY_SERIALIZER = RedisSerializer.string();

    /**
     * 1.若使用GenericFastJsonRedisSerializer来序列化对象在redis中的value值,它会以JSON的格式将值保存在redis中,可读性好,但这个对象必须要有个无参构造方法,否则报错
     * 2.若使用JdkSerializationRedisSerializer,它会以二进制的格式将值保存在redis中,可读性差
     * 3.若使用GenericJackson2JsonRedisSerializer,序列化和反序列化Java8时间类型的字段时会报错
     * ,需要在字段上加上:@JsonSerialize(using = LocalDateTimeSerializer.class)和@JsonDeserialize(using = LocalDateTimeDeserializer.class)
     */
    private static final RedisSerializer<Object> VALUE_SERIALIZER = RedisSerializer.json();

    /*****************************************************************************************************************/

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(KEY_SERIALIZER);
        redisTemplate.setValueSerializer(VALUE_SERIALIZER);
        redisTemplate.setHashKeySerializer(KEY_SERIALIZER);
        redisTemplate.setHashValueSerializer(VALUE_SERIALIZER);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * Redis缓存管理器(使用注解时)
     *
     * @param redisConnectionFactory RedisConnectionFactory
     * @return CacheManager
     */
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        // Redis缓存配置
        RedisCacheConfiguration config = RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(KEY_SERIALIZER))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(VALUE_SERIALIZER))
                // 设置缓存默认有效期(全局)
                .entryTtl(CacheConstants.GLOBAL_REDIS_TTL)
                // 不缓存null值
                .disableCachingNullValues();
        return RedisCacheManager
                .builder(redisConnectionFactory)
                .cacheDefaults(config)
                // 配置同步修改或删除 @CachePut/@CacheEvict
                .transactionAware()
                // 设置缓存有效期(单个)
                // .withCacheConfiguration("cache_user", getRedisCacheConfiguration(30))
                .build();
    }

    /**
     * 自定义key后缀
     *
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> "";
    }
}
